:- module(m_map).
:- export remove_smallest / 4.
:- export optimize / 2.
:- export apply_to_list / 3.
:- export select / 3.
:- export overlay / 3.
:- export merge / 3.
:- export from_corresponding_lists / 3.
:- export count / 2.
:- export det_remove / 4.
:- export remove / 4.
:- export delete_list / 3.
:- export delete / 3.
:- export from_sorted_assoc_list / 2.
:- export from_assoc_list / 2.
:- export to_sorted_assoc_list / 2.
:- export to_assoc_list / 2.
:- export values / 2.
:- export sorted_keys / 2.
:- export keys / 2.
:- export set / 4.
:- export det_update / 4.
:- export update / 4.
:- export det_insert_from_assoc_list / 3.
:- export det_insert_from_corresponding_lists / 4.
:- export det_insert / 4.
:- export insert / 4.
:- export inverse_search / 3.
:- export upper_bound_lookup / 4.
:- export upper_bound_search / 4.
:- export lower_bound_lookup / 4.
:- export lower_bound_search / 4.
:- export lookup / 3.
:- export search / 3.
:- export member / 3.
:- export contains / 2.
:- export is_empty / 1.
:- export init / 1.
:- comment(summary, "The `map' abstract data type.").
:- comment(author, "Fergus Henderson and Thomas Conway (Mercury) and Warwick Harvey (ECLiPSe)").
:- comment(desc, html("\t<P>\n\tThis module provides the `map' abstract data type.  A map, also\n\tknown as a dictionary or an associative array, is a collection of\n\tkey/value pairs which allows you to look up any data item given its\n\tkey.\n\t</P>\n\t<P>\n\tNote that keys must be ground, but values are allowed to be \n\tvariables.\n\t</P>\n\t")).
:- comment(apply_to_list / 3, [amode : apply_to_list(++, +, ?), args : ["KeyList" : "A list of keys to map", "Map" : "The map to apply", "ValueList" : "The list of corresponding values"], summary : "Map a list of keys to their corresponding values.", fail_if : "Fails if ValueList does not unify with the list of values corresponding to KeyList.", resat : no, see_also : [lookup / 3], desc : html("\t<P>\n\tThis predicate applies the map Map to a list of keys KeyList to\n\tproduce the list of values ValueList; i.e. it maps a list of keys\n\tto their corresponding values.  If one of the keys in KeyList is\n\tnot found in Map, then the predicate aborts witha runtime error.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(contains / 2, [amode : contains(+, ++), args : ["Map" : "A map", "Key" : "The key to look for"], summary : "Check whether a map contains a key.", fail_if : "Fails if Key does not appear in Map.", resat : no, see_also : [search / 3, keys / 2, sorted_keys / 2], desc : html("\t<P>\n\tThis predicate checks the map Map to see whether it contains an\n\tentry with key Key.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(count / 2, [amode : count(+, ?), args : ["Map" : "A map", "Count" : "The number of elements in Map"], summary : "Count the number of elements in a map.", fail_if : "Fails if Count does not unify with the number of elements in Map.", resat : no, desc : html("\t<P>\n\tCounts the number of elements in the map Map, and attempts to\n\tunify the result with Count.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(delete / 3, [amode : delete(+, ++, -), args : ["Map0" : "A map", "Key" : "The key to delete", "Map" : "The map after deletion"], summary : "Delete a key/value pair from a map.", fail_if : "Never fails.", resat : no, see_also : [delete_list / 3, remove / 4], desc : html("\t<P>\n\tIf the key Key appears in the map Map0, then remove it and its\n\tcorresponding value, resulting in the map Map.  If the key Key\n\tdoes not appear, Map is simply bound to Map0.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(delete_list / 3, [amode : delete_list(+, ++, -), args : ["Map0" : "A map", "KeyList" : "A list of keys to delete", "Map" : "The map after deletions"], summary : "Delete a list of key/value pairs from a map.", fail_if : "Never fails.", resat : no, see_also : [delete / 3, remove / 4], desc : html("\t<P>\n\tThis predicate takes a map Map0, and for each key in KeyList,\n\tcalls delete/3 to delete the key and its corresponding\n\tvalue.  The result after all the deletions is the map Map.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(det_insert / 4, [amode : det_insert(+, ++, ?, -), args : ["Map0" : "A map", "Key" : "A key to insert", "Value" : "The value corresponding to Key", "Map" : "The map after insertion"], summary : "Insert a key/value pair into a map, aborting if the key already exists.", fail_if : "Never fails.", resat : no, see_also : [insert / 4, update / 4, det_update / 4, set / 4], desc : html("\t<P>\n\tThis predicate inserts the key Key with corresponding value Value\n\tinto the map Map0, resulting in the map Map.  If the key Key is\n\talready in the map, then the predicate aborts with a runtime error.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(det_insert_from_assoc_list / 3, [amode : det_insert_from_assoc_list(+, +, -), args : ["Map0" : "A map", "List" : "A list of Key-Value pairs to insert", "Map" : "The map after insertion"], summary : "Insert key/value pairs into a map, aborting if any of the keys already exist.", fail_if : "Never fails.", resat : no, see_also : [det_insert / 4, det_insert_from_corresponding_lists / 4, from_assoc_list / 2, from_sorted_assoc_list / 2], desc : html("\t<P>\n\tThis predicate takes a map Map0, and for each entry in List (of\n\tthe form Key-Value), calls det_insert/4 to insert the\n\tKey/Value pair into the map.  The result after all the insertions\n\tis the map Map.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(det_insert_from_corresponding_lists / 4, [amode : det_insert_from_corresponding_lists(+, ++, ?, -), args : ["Map0" : "A map", "KeyList" : "A list of keys to insert", "ValueList" : "A list of values corresponding to the keys in KeyList", "Map" : "The map after insertion"], summary : "Insert key/value pairs into a map, aborting if any of the keys already exist.", fail_if : "Fails if the lists aren't the same length.", resat : no, see_also : [det_insert / 4, det_insert_from_assoc_list / 3, from_corresponding_lists / 3], desc : html("\t<P>\n\tThis predicate takes a map Map0, and for each key Key in KeyList\n\tand corresponding value Value from ValueList, calls\n\tdet_insert/4 to insert the Key/Value pair into the map.\n\tThe result after all the insertions is the map Map.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(det_remove / 4, [amode : det_remove(+, ++, ?, -), args : ["Map0" : "A map", "Key" : "The key to remove", "Value" : "The value corresponding to Key", "Map" : "The map after removal"], summary : "Remove a key/value pair from a map, aborting if the key is not present.", fail_if : "Fails if Value does not unify with the value corresponding to Key.", resat : no, see_also : [delete / 3, remove / 4], desc : html("\t<P>\n\tThis predicate removes the key Key and its corresponding value from\n\tthe map Map0, resulting in the map Map.  It then attempts to\n\tunify the removed value with Value.  If the key Key was not in the\n\tmap Map0, then the predicate aborts with a runtime error.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(det_update / 4, [amode : det_update(+, ++, ?, -), args : ["Map0" : "A map", "Key" : "A key to update", "Value" : "The value corresponding to Key", "Map" : "The map after updating"], summary : "Update the value corresponding to a key in a map, aborting if it doesn't exist.", fail_if : "Never fails.", resat : no, see_also : [update / 4, insert / 4, det_insert / 4, set / 4], desc : html("\t<P>\n\tIf the key Key already exists in the map Map0, then this\n\tpredicate updates the corresponding value to be Value, resulting\n\tin the map Map.  If the key Key is not already in the map,\n\tthen the predicate aborts with a runtime error.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(from_assoc_list / 2, [amode : from_assoc_list(+, -), args : ["AssocList" : "A list of key-value pairs", "Map" : "A map"], summary : "Converts an association list into a map.", fail_if : "Never fails.", resat : no, see_also : [to_assoc_list / 2, from_sorted_assoc_list / 2], desc : html("\t<P>\n\tAssocList is a list of key/value pairs of the form Key-Value, \n\tand Map is a map containing these key/value pairs.  If a key\n\tappears more than once in AssocList, then its corresponding value\n\tin the map Map will be the last one appearing in AssocList.  \n\t</P>\n\t")]).
:- comment(from_corresponding_lists / 3, [amode : from_corresponding_lists(++, ?, -), args : ["KeyList" : "A list of keys", "ValueList" : "A list of values corresponding to the keys in KeyList", "Map" : "The created map"], summary : "Converts a corresponding pair of lists into a map.", fail_if : "Fails if the lists aren't the same length.", resat : no, see_also : [from_assoc_list / 2, det_insert_from_corresponding_lists / 4], desc : html("\t<P>\n\tConverts a list of keys KeyList and a corresponding list of values\n\tValueList into a map Map.  If a key appears more than once in\n\tKeyList, then its corresponding value in the map Map will be\n\tthe last one appearing in AssocList.\n\t</P>\n\t")]).
:- comment(from_sorted_assoc_list / 2, [amode : from_sorted_assoc_list(+, -), args : ["AssocList" : "A sorted list of key-value pairs", "Map" : "A map"], summary : "Converts a sorted association list into a map.", fail_if : "Never fails.", resat : no, see_also : [to_sorted_assoc_list / 2, from_assoc_list / 2], desc : html("\t<P>\n\tAssocList is a sorted list of key/value pairs of the form Key-Value,\n\tand Map is a map containing these key/value pairs.  If a key\n\tappears more than once in AssocList, then its corresponding value\n\tin the map Map will be the last one appearing in AssocList.\n\t</P>\n\t")]).
:- comment(init / 1, [amode : init(-), args : ["Map" : "The new map"], summary : "Initialise a new (empty) map.", fail_if : "Never fails.", resat : no, see_also : [is_empty / 1]]).
:- comment(insert / 4, [amode : insert(+, ++, ?, -), args : ["Map0" : "A map", "Key" : "A key to insert", "Value" : "The value corresponding to Key", "Map" : "The map after insertion"], summary : "Insert a key/value pair into a map, failing if the key already exists.", fail_if : "Fails if Key already appears in Map0.", resat : no, see_also : [det_insert / 4, update / 4, det_update / 4, set / 4], desc : html("\t<P>\n\tThis predicate inserts the key Key with corresponding value Value\n\tinto the map Map0, resulting in the map Map.  If the key Key is\n\talready in the map, then the predicate fails.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(inverse_search / 3, [amode : inverse_search(+, ?, ?), args : ["Map" : "A map", "Value" : "A value to search for", "Key" : "A key corresponding to Value"], summary : "Search a map for a value.", fail_if : "Fails if Value does not appear in Map or if Key does not unify with any corresponding keys found.", resat : yes, see_also : [search / 3, member / 3], desc : html("\t<P>\n\tThis predicate searches the map Map for value entries which unify\n\twith Value.  If such a value is found, then it attempts to unify the\n\tcorresponding key with Key.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(is_empty / 1, [amode : is_empty(+), args : ["Map" : "A map"], summary : "Check whether a map is empty.", fail_if : "Fails if Map is not an empty map.", resat : no, see_also : [init / 1]]).
:- comment(keys / 2, [amode : keys(+, -), args : ["Map" : "A map", "KeyList" : "A list of all the keys from Map"], summary : "Return all the keys from a map.", fail_if : "Never fails.", resat : no, see_also : [sorted_keys / 2, values / 2], desc : html("\t<P>\n\tKeyList is a list of all the keys appearing in the map Map.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(lookup / 3, [amode : lookup(+, ++, ?), args : ["Map" : "A map", "Key" : "A key to search for", "Value" : "The value corresponding to Key"], summary : "Search a map for a key.", fail_if : "Fails if Value does not unify with the value corresponding to Key.", resat : no, see_also : [member / 3, search / 3], desc : html("\t<P>\n\tThis predicate searches the map Map for an entry with key Key.\n\tIf the key is found, then it attempts to unify the corresponding\n\tvalue with Value.  If the key is not found, then it aborts with\n\ta runtime error.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(lower_bound_lookup / 4, [amode : lower_bound_lookup(+, ++, ?, ?), args : ["Map" : "A map", "SearchKey" : "A key to search for", "Key" : "The key found", "Value" : "The value corresponding to Key"], summary : "Search a map for the smallest key no smaller than SearchKey.", fail_if : "Fails if Key and Value do not unify with the key and value found.", resat : no, see_also : [lower_bound_search / 4, upper_bound_search / 4, upper_bound_lookup / 4], desc : html("\t<P>\n\tThis predicate searches the map Map for the entry with the\n\tsmallest key which is no smaller than SearchKey.  If such a key is\n\tfound, then it attempts to unify it with Key and the corresponding\n\tvalue with Value.  If such a key is not found, then it aborts with\n\ta runtime error.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(lower_bound_search / 4, [amode : lower_bound_search(+, ++, ?, ?), args : ["Map" : "A map", "SearchKey" : "A key to search for", "Key" : "The key found", "Value" : "The value corresponding to Key"], summary : "Search a map for the smallest key no smaller than SearchKey.", fail_if : "Fails if there are no keys at least as large as SearchKey in Map or if Key and Value do not unify with the key and value found.", resat : no, see_also : [lower_bound_lookup / 4, upper_bound_search / 4, upper_bound_lookup / 4], desc : html("\t<P>\n\tThis predicate searches the map Map for the entry with the\n\tsmallest key which is no smaller than SearchKey.  If such a key is\n\tfound, then it attempts to unify it with Key and the corresponding\n\tvalue with Value.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(member / 3, [amode : member(+, ?, ?), args : ["Map" : "A map", "Key" : "A key from Map", "Value" : "The value in Map corresponding to Key"], summary : "Succeeds if Key and Value unify with a key/value pair from Map.", fail_if : "Fails if Key and Value do not unify with a key/value pair from Map.", resat : yes, see_also : [search / 3, lookup / 3], desc : html("\t<P>\n\tTries to unify Key and Value with key/value pairs from the map Map.\n\t</P>\n\t<P>\n\tIf Key and Value are variables and Map is a map, then all\n\tmembers of the map Map are found on backtracking.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(merge / 3, [amode : merge(+, +, -), args : ["MapA" : "A map to merge", "MapB" : "The other map to merge", "Map" : "The merged map"], summary : "Merges two maps into one.", fail_if : "Never fails.", resat : no, see_also : [overlay / 3], desc : html("\t<P>\n\tThe map Map is the result of merging the map MapA and the map MapB;\n\ti.e. Map contains all the key/value pairs from both MapA and MapB.\n\tIf MapA and MapB have a key in common, then it is not defined\n\twhich corresponding value will end up associated with that key\n\tin Map.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(optimize / 2, [amode : optimize(+, -), args : ["Map0" : "A map to optimize", "Map" : "The optimized map"], summary : "Optimize a map for many lookups but few/no modification.", fail_if : "Never fails.", resat : no, desc : html("\t<P>\n\tDeclaratively, this predicate does nothing (i.e. the map Map is\n\tequivalent to the map Map0).  However, operationally it suggests to\n\tthe implementation that the representation of the map be optimised\n\tfor lookups, with few or no modifications to be expected.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(overlay / 3, [amode : overlay(+, +, -), args : ["MapA" : "A map", "MapB" : "The map to overlay", "Map" : "The resulting map"], summary : "Overlays one map over another.", fail_if : "Never fails.", resat : no, see_also : [merge / 3], desc : html("\t<P>\n\tThe map Map contains a key/value pair for every key that appears in\n\teither the map MapA or the map MapB.  If a key Key appears in MapB,\n\tthen its corresponding value in Map is that appearing in MapB;\n\totherwise it is that appearing in MapA.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(remove / 4, [amode : remove(+, ++, ?, -), args : ["Map0" : "A map", "Key" : "The key to remove", "Value" : "The value corresponding to Key", "Map" : "The map after removal"], summary : "Remove a key/value pair from a map, failing if the key is not present.", fail_if : "Fails is Key does not appear in Map0 or if Value does not unify with the corresponding value.", resat : no, see_also : [delete / 3, det_remove / 4, remove_smallest / 4], desc : html("\t<P>\n\tIf the key Key appears in the map Map0, then remove it and attempt\n\tto unify its corresponding value with Value.  Map is Map0 with the\n\tkey removed.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(remove_smallest / 4, [amode : remove_smallest(+, ?, ?, -), args : ["Map0" : "A map", "Key" : "The key removed", "Value" : "The value corresponding to Key", "Map" : "The map after removal"], summary : "Remove the smallest key and its corresponding value from a map.", fail_if : "Fails if Map0 is empty or if Key and Value do not unify with the key and value removed.", resat : no, see_also : [remove / 4], desc : html("\t<P>\n\tRemoves the smallest key in the map Map0 (resulting in the\n\tmap Map), and attempts to unify the removed key with Key and\n\tits corresponding value with Value.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(search / 3, [amode : search(+, ++, ?), args : ["Map" : "A map", "Key" : "A key to search for", "Value" : "The value corresponding to Key"], summary : "Search a map for a key.", fail_if : "Fails if Key does not appear in Map or if Value does not unify with the corresponding value found.", resat : no, see_also : [member / 3, lookup / 3, inverse_search / 3], desc : html("\t<P>\n\tThis predicate searches the map Map for an entry with key Key.\n\tIf the key is found, then it attempts to unify the corresponding\n\tvalue with Value.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(select / 3, [amode : select(+, ++, -), args : ["Map0" : "A map", "KeyList" : "A list of keys to select", "Map" : "The resulting map"], summary : "Creates a new map containing just those entries corresponding to a given list of keys.", fail_if : "Never fails.", resat : no, desc : html("\t<P>\n\tThe map Map contains the key/value pairs from the map Map0 where\n\tthe key appears in the list KeyList.  Keys in KeyList which do not\n\tappear in Map0 are ignored.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(set / 4, [amode : set(+, ++, ?, -), args : ["Map0" : "A map", "Key" : "A key to set", "Value" : "The value corresponding to Key", "Map" : "The map after setting"], summary : "Update the value corresponding to a key in a map, inserting the key if it doesn't exist already.", fail_if : "Never fails.", resat : no, see_also : [insert / 4, det_insert / 4, update / 4, det_update / 4], desc : html("\t<P>\n\tIf the key Key already exists in the map Map0, then this predicate\n\tupdates the corresponding value to be Value.  Otherwise it inserts\n\tthe key Key into the map with value Value.  The resulting map is\n\tMap.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(sorted_keys / 2, [amode : sorted_keys(+, -), args : ["Map" : "A map", "KeyList" : "A list of all the keys from Map"], summary : "Return all the keys from a map, in sorted order.", fail_if : "Never fails.", resat : no, see_also : [keys / 2, values / 2], desc : html("\t<P>\n\tKeyList is a list of all the keys appearing in the map Map, in\n\tsorted order.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(to_assoc_list / 2, [amode : to_assoc_list(+, -), args : ["Map" : "A map", "AssocList" : "A list of the key-value pairs from Map"], summary : "Converts a map into an association list.", fail_if : "Never fails.", resat : no, see_also : [to_sorted_assoc_list / 2, from_assoc_list / 2], desc : html("\t<P>\n\tAssocList is a list containing the key/value pairs from the map\n\tMap, in the form Key-Value.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(to_sorted_assoc_list / 2, [amode : to_sorted_assoc_list(+, -), args : ["Map" : "A map", "AssocList" : "A sorted list of the key-value pairs from Map"], summary : "Converts a map into a (sorted) association list.", fail_if : "Never fails.", resat : no, see_also : [to_assoc_list / 2, from_sorted_assoc_list / 2], desc : html("\t<P>\n\tAssocList is a sorted list containing the key/value pairs from the\n\tmap Map, in the form Key-Value.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(update / 4, [amode : update(+, ++, ?, -), args : ["Map0" : "A map", "Key" : "A key to update", "Value" : "The value corresponding to Key", "Map" : "The map after updating"], summary : "Update the value corresponding to a key in a map.", fail_if : "Fails if Key does not appear in Map0.", resat : no, see_also : [det_update / 4, insert / 4, det_insert / 4, set / 4], desc : html("\t<P>\n\tIf the key Key already exists in the map Map0, then this predicate\n\tupdates the corresponding value to be Value.  The resulting map is\n\tMap.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(upper_bound_lookup / 4, [amode : upper_bound_lookup(+, ++, ?, ?), args : ["Map" : "A map", "SearchKey" : "A key to search for", "Key" : "The key found", "Value" : "The value corresponding to Key"], summary : "Search a map for the largest key no larger than SearchKey.", fail_if : "Fails if Key and Value do not unify with the key and value found.", resat : no, see_also : [lower_bound_search / 4, lower_bound_lookup / 4, upper_bound_search / 4], desc : html("\t<P>\n\tThis predicate searches the map Map for the entry with the\n\tlargest key which is no larger than SearchKey.  If such a key is\n\tfound, then it attempts to unify it with Key and the corresponding\n\tvalue with Value.  If such a key is not found, then it aborts with\n\ta runtime error.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(upper_bound_search / 4, [amode : upper_bound_search(+, ++, ?, ?), args : ["Map" : "A map", "SearchKey" : "A key to search for", "Key" : "The key found", "Value" : "The value corresponding to Key"], summary : "Search a map for the largest key no larger than SearchKey.", fail_if : "Fails if there are no keys at least as large as SearchKey in Map or if Key and Value do not unify with the key and value found.", resat : no, see_also : [lower_bound_search / 4, lower_bound_lookup / 4, upper_bound_lookup / 4], desc : html("\t<P>\n\tThis predicate searches the map Map for the entry with the\n\tlargest key which is no larger than SearchKey.  If such a key is\n\tfound, then it attempts to unify it with Key and the corresponding\n\tvalue with Value.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
:- comment(values / 2, [amode : values(+, -), args : ["Map" : "A map", "ValueList" : "A list of all the values from Map"], summary : "Return all the values from a map.", fail_if : "Never fails.", resat : no, see_also : [values / 2], desc : html("\t<P>\n\tValueList is a list of all the values appearing in the map Map.\n\t</P>\n\t<P>\n\tThis predicate should only be called with maps created by other\n\tpredicates from the map module.\n\t</P>\n\t")]).
